/*
 * dbm_lsdb_manager.c
 *
 *  Created on: 2012-12-11
 *      Author: macro
 */


#include "lsdb/lsdb.h"
#include "cmn/util.h"
#include "cmn/err_code.h"
#include "lsdb/dbm_lsdb_manager.h"
#include <time.h>
#include "lsdb/dbm_lsdb_handle.h"
#include "server/dbm_socket.h"
#include "timer/timer.h"
#include "server/dbm_server.h"
struct dbmanager* dbList;

int dbm_manager_init(){
	dbList = malloc_z(struct dbmanager);
	dbList->next = NULL;
	dbList->areas  = dbm_area_init();
	assert(NO_ERR == cr_lsdb_init(&dbList->lsdb));
	//dbList->lidb;
	return NO_ERR;
}

struct ospf_area*  dbm_area_init(){//only used by inner functions
	struct ospf_area* n_area = malloc_z(struct ospf_area);
		n_area->next = NULL;
		n_area->area_id = 0; //默认创建0的area
		n_area->lsList = NULL;
		return n_area;
}

struct ospf_area* create_dbm_area(u_int32_t area){//only used by inner functions
	struct ospf_area* n_area = malloc_z(struct ospf_area);
	n_area->next = NULL;
	n_area->area_id = area;
	n_area->lsList = NULL;
	return n_area;
}

struct dbmanager* create_dbm_manager(u_int32_t area){
	struct dbmanager* dbm = dbList;
	for(dbm;dbm->next!=NULL;dbm=dbm->next);
	struct dbmanager* n_db = malloc_z(struct dbmanager);
	n_db->areas = create_dbm_area(area);
	int err_code;
	if((err_code = cr_lsdb_init((id_t*)&(n_db->lsdb))) != NO_ERR)
				return err_code;
	//az->lidb =   cr_ddc_database_init(az->lidb);
	n_db->next = NULL;
	dbm->next = n_db;
	return n_db;
}

int find_dbm_manager(u_int32_t area){
	struct dbmanager* dbm = dbList;
	for(dbm;dbm!=NULL;dbm=dbm->next){
		if(dbm->areas->area_id == area)
			return FOUND;
	}
	return NOTFOUND;
}

struct dbmanger* get_dbm_manager(u_int32_t area){
	struct dbmanager* dbm = dbList;
		for(dbm;dbm!=NULL;dbm=dbm->next){
			if(dbm->areas->area_id == area)
			{
				printf("found the area %d\n",dbm->areas->area_id);
				return dbm;
			}
		}
		return NULL;
}

//if the add action is success, return the area_id,else return -1
int add_link_state_to_area(struct cr_lsdb_link_state* lsa,u_int32_t area_id){
	struct dbmanager* db;
	if(NOTFOUND == find_dbm_manager(area_id)){//new area's linkstate
		db = create_dbm_manager(area_id);
	}
	else
	{
		db = get_dbm_manager(area_id);
	}
	cr_lsdb_link_state_add(lsa,db->lsdb);
	return -1;
}

int update_link_state_to_area(struct cr_lsdb_link_state* lsa,u_int32_t area_id){
	assert(find_dbm_manager(area_id)==FOUND);
	struct dbmanager* db;
	db = get_dbm_manager(area_id);
	cr_lsdb_link_state_update(lsa,db->lsdb);
	return 0;
}

int find_link_state_to_area(struct link_state_key* key,struct cr_lsdb_link_state* lsa,u_int32_t area_id){
	struct dbmanager* db;
	if(NOTFOUND == find_dbm_manager(area_id))
	{
		return NOTFOUND;
	}
	else
	{
		db =get_dbm_manager(area_id);
		int r = cr_lsdb_link_state_find(key,lsa,db->lsdb);
		if(!r){
			return FOUND;
		}
		return NOTFOUND;
	}
}


int print_lsdb(struct cr_lsdb_router* rt, struct cr_lsdb_link_state* state, void* args){
	printf("Router[%d]:\n",rt->id);
	printf("LSA:R-ID[%d],R-IF[%d],N-ID[%d],N-IF[%d],Metric[%d]\n",state->key.rt_id,state->key.if_id,state->key.n_rt_id,state->key.n_if_id,state->metric);
	return 0;
}
/*
int add_link_state_to_lsdb(struct cr_lsdb_link_state* lsa,u_int32_t area_id){
	if(NOTFOUND == find_dbm_manger(area_id)){
		struct dbmanager* dbm = create_dbm_manger(area_id);
		az->az_lsdb_head->next = NULL;
		int result = cr_lsdb_link_state_add(lsa,az->lsdb);

	}
	else
	{
		struct dbm_autonomous_zone* az = get_autonomous_zone(az_id,az_head);
		struct az_lsdb* azlsdb_handle = az->az_lsdb_head;
		for(;azlsdb_handle->next != NULL;azlsdb_handle = azlsdb_handle->next){
		}
		struct az_lsdb* newlsa = malloc_z(struct az_lsdb);
		newlsa->ls = lsa;
		newlsa->next = NULL;

		azlsdb_handle->next = newlsa;
		cr_lsdb_link_state_add(lsa,az->lsdb);
	}
}
int update_link_state_to_lsdb(struct cr_lsdb_link_state* lsa,u_int32_t az_id,struct dbm_autonomous_zone* head){
	assert(FOUND == find_autonomous_zone(az_id,head));
	struct dbm_autonomous_zone* handle = get_autonomous_zone(az_id,head);
	cr_lsdb_link_state_update(lsa,handle->lsdb);
}
int find_link_state(struct link_state_key* key,struct cr_lsdb_link_state* lsa,u_int32_t az_id,struct dbm_autonomous_zone* head)
{
	assert(FOUND== find_autonomous_zone(az_id,head));
	struct dbm_autonomous_zone* handle =get_autonomous_zone(az_id,head);
	if(NOT_FOUND_ERR==cr_lsdb_link_state_find(key,lsa,handle->lsdb))
	{
		return NOTFOUND;
	}
	return FOUND;
}
*/

void* dbm_save_snapshoot(void* args){
		u_int32_t rt_id;
		memset(global_snapshoot,0,global_snapshoot_len);
		rt_id = dbList->r_id;
		struct dbmanager* db = dbList;
		char * data = global_snapshoot;
		sprintf(data,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
						"<PMA_LOCAL_INFO>\n"
						"<ROUTER id=\"%d\">\n",rt_id);
		data = data + strlen(data);
		time_t raw_time;
				struct tm* time_info;
				time(&raw_time);
				time_info = localtime(&raw_time);
				sprintf(data,"<timestamp>%4d-%d-%d %d:%d:%d</timestamp>\n",
						1900+time_info->tm_year,
						1+time_info->tm_mon,
						time_info->tm_mday,
						time_info->tm_hour,
						time_info->tm_min,
						time_info->tm_sec);
				data = data + strlen(data);
		while(db!=NULL){
			id_t lsdb_handle = db->lsdb;
			dbm_get_lsdb(db->areas->area_id,&data);
			db = db->next;
		}

		sprintf(data,"</ROUTER>\n</PMA_LOCAL_INFO>\n");
		global_snapshoot_len = strlen(global_snapshoot);
		printf("finish %d bytes\n",global_snapshoot_len);
		printf("%s\n",global_snapshoot);
}

void* dbm_create_snapshoot(FILE* fp){

	u_int32_t rt_id;
	rt_id = dbList->r_id;
	struct dbmanager* db = dbList;

	if(fp == NULL){
				perror("[DBM]Buffer file open fail!");
				return -1;
			}
	fprintf(fp,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
					"<PMA_LOCAL_INFO>\n"
					"<ROUTER id=\"%d\">\n",rt_id);
	time_t raw_time;
			struct tm* time_info;
			time(&raw_time);
			time_info = localtime(&raw_time);
			fprintf(fp,"<timestamp>%4d-%d-%d %d:%d:%d</timestamp>\n",
					1900+time_info->tm_year,
					1+time_info->tm_mon,
					time_info->tm_mday,
					time_info->tm_hour,
					time_info->tm_min,
					time_info->tm_sec);
	while(db!=NULL){
		id_t lsdb_handle = db->lsdb;
		//dbm_get_lsdb(fp,db->areas->area_id);
		db = db->next;
	}

	fprintf(fp,"</ROUTER>\n</PMA_LOCAL_INFO>\n");

}

void* send_lsdb_snap_shoot(void* args){
	//printf("here is bug\n");
	dbm_save_snapshoot(args);
//	printf("file :len%d\n",global_snapshoot_len);
	struct packet* pkt = malloc_z(struct packet);
	pkt->sockfd = global_bm_sock;
	u_char* msg = (u_char*)malloc(sizeof(Packet_header)+global_snapshoot_len);
	Packet_header p_header;// = (Packet_headerp)malloc(sizeof(Packet_header)+global_snapshoot_len);
	p_header.sour_module = DBM;
	p_header.dest_module = PMS;
	p_header.action = LSDB;
	p_header.length = global_snapshoot_len;
	memcpy(msg,&p_header,sizeof(Packet_header));
	memcpy(msg+sizeof(Packet_header),global_snapshoot,global_snapshoot_len);
	pkt->head = msg;
	pkt->len = p_header.length + sizeof(Packet_header);
	//printf("%d\n",pkt->len);
	pkt->body = msg;
	//printf("%s\n",pkt->body);
	//printf("%s\n",p_header+sizeof(Packet_header));


	//fclose(fp);
	unset_timer(timer_snapshoot);
	timer_snapshoot = -1;
	dbm_send_packet(pkt);

}

void* save_lsdb_to_file(void* args){
	FILE* fp = fopen(LSDB_XML_FILE,"wb");
	if(fp== NULL){
		printf("Open file Error!\n");
		return NULL;
	}
	fprintf(fp,global_snapshoot);
	fclose(fp);

}

int dbm_get_lsdb(u_int32_t area,char **data){
	sprintf(*data,"<LSDB>\n");
	*data = *data + strlen(*data);
	struct cr_lsdb_router * rt_head = NULL;
	struct cr_lsdb_router * rt_ptr = NULL;
	struct cr_lsdb_link_state * link_head = NULL;
	struct cr_lsdb_link_state * link_ptr = NULL;
	struct dbmanager* db = get_dbm_manager(area);
	assert((cr_lsdb_get_routers(&rt_head,db->lsdb))==0);
	rt_ptr = rt_head;
	while(rt_ptr)
	{
		sprintf(*data,"\t<router id=\"%d\">\n", rt_head->id);
		*data = *data + strlen(*data);
		assert(cr_lsdb_get_links_state_by_router(&link_head, rt_head->id,db->lsdb)==0);
		link_ptr = link_head;

		while(link_ptr){
			sprintf(*data,"\t\t<interface id=\"%d\">\n",link_ptr->key.if_id);
			*data = *data + strlen(*data);
			if(link_ptr->key.n_rt_id !=0)
			{
				sprintf(*data,"\t\t\t<area_id>%d</area_id>\n",area);
				*data = *data + strlen(*data);
			}
			sprintf(*data,"\t\t\t<neighbor_id>%d</neighbor_id>\n",link_ptr->key.n_rt_id);
			*data = *data + strlen(*data);
			sprintf(*data, "\t\t\t<neighbor_if>%d</neighbor_if>\n", link_ptr->key.n_if_id);
			*data = *data + strlen(*data);
			sprintf(*data, "\t\t\t<metric>%d</metric>\n", link_ptr->metric);
			*data = *data + strlen(*data);
			sprintf(*data, "\t\t\t<state>%d</state>\n", link_ptr->state);
			*data = *data + strlen(*data);
			sprintf(*data, "\t\t</interface>\n");
			*data = *data + strlen(*data);
			link_ptr = link_ptr->next;

						//in case of memory leak
			free(link_head);
			link_head = link_ptr;
		}
		sprintf(*data,"\t</router>\n");
		*data = *data + strlen(*data);
		rt_ptr = rt_ptr->next;
		free(rt_head);
		rt_head = rt_ptr;
	}
	sprintf(*data,"</LSDB>\n");
	*data = *data + strlen(*data);
	return NO_ERR;
}

int show_lsdb(u_int32_t area){
	if(NOTFOUND==find_dbm_manager(area)){
		return NOTFOUND;
	}
	else
	{
		struct dbmanager* handle = get_dbm_manager(area);
		cr_lsdb_links_state_accept(print_lsdb,NULL,handle->lsdb);
		return 0;
	}
}

int show_ls(struct cr_lsdb_link_state* lsa){
	printf("LSA:R-ID[%d],R-IF[%d],N-ID[%d],N-IF[%d],Metric[%d],State[%d]\n",lsa->key.rt_id,lsa->key.if_id,lsa->key.n_rt_id,lsa->key.n_if_id,lsa->metric,lsa->state);
}
int show_ls_pkt(struct link_state_pkt* lsa){
	printf("LSA:R-ID[%d],R-IF[%d],N-ID[%d],N-IF[%d]\n",lsa->rt_id,lsa->if_id,lsa->n_rt_id,lsa->n_if_id);
}

int show_az_info(u_int32_t area){
	if(NOTFOUND==find_dbm_manager(area)){
			return NOTFOUND;
	}
	else
	{
			struct dbmanager* handle = get_dbm_manager(area);
			printf("Routers:%d\n",cr_lsdb_get_routers_count(handle->lsdb));
			printf("Links:%d\n",cr_lsdb_get_link_states_count(handle->lsdb));
	}
	return 0;
}
